Skip to content

Speed up CI/CD runs, scope the developer CLI, and harden workflow hygiene#895

Merged
tjementum merged 15 commits into
mainfrom
pp-1209-share-webapplicationfactory-across-tests
May 15, 2026
Merged

Speed up CI/CD runs, scope the developer CLI, and harden workflow hygiene#895
tjementum merged 15 commits into
mainfrom
pp-1209-share-webapplicationfactory-across-tests

Conversation

@tjementum
Copy link
Copy Markdown
Member

@tjementum tjementum commented May 14, 2026

Summary & Motivation

A coordinated refresh of the CI/CD pipelines and developer CLI: faster runs, scoped commands, better observability, and consistent workflow conventions.

Test infrastructure

BackOfficeEndpointBaseTest and EndpointBaseTest<TContext> built a fresh WebApplicationFactory<Program> per test instance. With Meziantou.Xunit.ParallelTestFramework, every Account-API and BackOffice test paid a full ASP.NET Core cold-start. Both bases now share one host per test class via IClassFixture<...>, routing per-test state (SqliteConnection, telemetry collector, MockStripeState, IEmailClient) through AsyncLocal. New types: BackOfficeWebApplicationFactory + BackOfficeTestContext (26 derived classes) and AccountWebApplicationFactory + AccountTestContext (60 derived classes). MockStripeState becomes transient so per-request resolution reads the per-test instance; TestServer.PreserveExecutionContext = true keeps the AsyncLocal flowing into request handling.

Single Code Style workflow

A new code-style.yml replaces the per-SCS code-style work in account.yml, main.yml, app-gateway.yml. Four jobs:

  • detect-scope — classifies the diff via inline git diff, outputs the backend scope and format mode for the downstream jobs.
  • code-linting — backend inspectcode + frontend build + frontend lint (oxlint).
  • code-formatting — backend cleanupcode + frontend format check (oxfmt).
  • sonarcloud — runs once per push (previously three times, once per SCS), sequentially per slnf to keep test assemblies in separate processes and avoid the PortAllocation.Load() race.

Backend lint and format are scoped to a single SCS via --self-contained-system <name> when the diff touches only that SCS; cross-cutting changes fall back to the full solution. Code coverage is out of scope here — the dotCover path repeatedly exceeded 20 minutes against the new IClassFixture infrastructure and is tracked separately.

AppGateway tests now run in CI

AppGateway.Tests existed in the solution but was never executed — the slnf-scoped runs missed it, and app-gateway.yml had no test step. The workflow now runs dotnet test AppGateway.Tests/AppGateway.Tests.csproj --no-build with the same user-secret bootstrap the other workflows use.

Developer CLI: --gateway/-g scope flag

build, test, format, and lint accept --gateway/-g to scope to AppGateway only (mutually exclusive with -s). pp test -g targets AppGateway.Tests/AppGateway.Tests.csproj; lint/format scope JetBrains tools to AppGateway/** + AppGateway.Tests/**. Shared logic in AppGatewayHelper.

Faster format and lint

  • format defaults to changed-only (.cs files diffed vs origin/main); --all-files for full sweep. CI auto-flips to --all-files when application/dotnet-tools.json changes, so JetBrains tool upgrades catch latent drift.
  • lint --changed-only is opt-in; CI lints full because inspectcode has cross-file rules.
  • Dropped the temp-.slnf workaround for cleanupcode — JetBrains 2026.1 accepts .slnx directly.

Workflow hygiene

  • Concurrency on every top-level workflow with cancel-in-progress: true (and false for reusable deploy workflows so mid-deploy cancellations cannot leave a half-applied state).
  • Inspection results on failure: code-style.yml and developer-cli.yml dump result.json to the run console and $GITHUB_STEP_SUMMARY. Replaces the brittle grep | tee exit-code contract.
  • Removed leftover SonarScanner steps and Java JDK setup from account.yml and main.yml (centralized in code-style.yml).
  • Removed stale _preview-migrations.yml trigger-path references (file does not exist).
  • YAML hygiene pass across all workflows: blank lines, canonical argument order, trailing whitespace.

Database Plan reuses Build and Test artifacts

build-and-test uploads application/**/bin and application/**/obj as a <scs>-build artifact (when staging is enabled). _migrate-database.yml downloads it and restores NuGet, skipping the redundant checkout + setup + build chain.

E2E test fix piggy-backed on this branch

Two e2e tests inherited from the recently-merged feature-flags work failed on a default-seeded database (feature-flag-flows.spec.ts:262, user-management-flows.spec.ts:473). Root cause: account-overview and compact-view are registered with isKillSwitchEnabled: true, so the startup reconciler creates them inactive (EnabledAt = null); the configurable-flags handlers filter inactive rows out, the API returns empty, and FeaturesSection / PreferencesFeatureFlagsSection render null. The tests now activate the kill-switch flags via the back-office activate endpoint during setup — test-only fix, no production code, no seeder change.

CI benchmark

The biggest CI win comes from the Database Staging migration-skip gate on account.yml / main.yml — PRs that do not change EF migration files skip the Database Staging job entirely.

Workflow BEFORE AFTER, no migrations AFTER, with migrations Δ (no migrations) Δ (with migrations)
Account 9m00s 2m49s 6m17s -69% -30%
Main 6m41s 1m55s 5m40s -71% -15%
AppGateway 7m26s 1m26s 1m26s -81% -81%
Code Style - 4m48s 4m48s new new
Critical path per push 9m00s 4m48s 6m17s -47% -30%
Total CI minutes per push 23m07s 15m19s 22m34s -34% -2%

AppGateway's delta is large because code-linting and code-formatting moved out of app-gateway.yml into the consolidated code-style.yml. On the no-migrations path the critical path now sits on Code Style (parallel lint/format/sonar jobs each paying setup); sharing the backend build artifact across them is an obvious follow-up. On the with-migrations path the critical path stays on account.yml.

Downstream projects with a substantial Main SCS will see a bigger lift than this suggests — the slowest CI step used to be backend cleanupcode running on every file; it now inspects only changed .cs files. Main and Account now sit close in wall-clock despite Account having materially more code, because the npm + dotnet restore + build setup now dominates.

Test-step benchmark (isolated)

Test-host refactor measured in isolation (Code Style and Database Staging disabled; 5 samples per side):

Run 1 Run 2 Run 3 Run 4 Run 5 Mean Stddev
AFTER (BackOffice + Account shared host) 2m18s 2m26s 2m21s 2m21s 2m21s 2m21s 2.9s
BEFORE (per-test host, baseline) 3m46s 3m51s 3m38s 3m41s 3m54s 3m46s 6.7s

Δ -37% on the test step alone, stddev more than halves — the runs are markedly more stable too.

Checklist

  • I have added tests, or done manual regression tests
  • I have updated the documentation, if necessary

@tjementum tjementum added the Enhancement New feature or request label May 14, 2026
@tjementum tjementum self-assigned this May 14, 2026
@linear
Copy link
Copy Markdown

linear Bot commented May 14, 2026

@tjementum tjementum closed this May 14, 2026
@tjementum tjementum force-pushed the pp-1209-share-webapplicationfactory-across-tests branch from 0440bae to 1da4403 Compare May 14, 2026 10:02
@tjementum tjementum reopened this May 14, 2026
@tjementum tjementum force-pushed the pp-1209-share-webapplicationfactory-across-tests branch from 0440bae to acacc4b Compare May 14, 2026 10:05
@tjementum tjementum moved this to 🏗 In Progress in Kanban board May 14, 2026
@tjementum tjementum force-pushed the pp-1209-share-webapplicationfactory-across-tests branch from acacc4b to 69d9c50 Compare May 14, 2026 10:20
@tjementum tjementum requested a review from a team as a code owner May 14, 2026 10:20
@tjementum tjementum force-pushed the pp-1209-share-webapplicationfactory-across-tests branch 3 times, most recently from 0592515 to 719edf2 Compare May 14, 2026 10:56
@tjementum tjementum changed the title Share WebApplicationFactory across BackOffice tests via IClassFixture Share WebApplicationFactory across BackOffice and Account tests via IClassFixture May 14, 2026
@tjementum tjementum force-pushed the pp-1209-share-webapplicationfactory-across-tests branch 4 times, most recently from f80592d to 9587ec5 Compare May 14, 2026 13:38
@tjementum tjementum changed the title Share WebApplicationFactory across BackOffice and Account tests via IClassFixture Share WebApplicationFactory across BackOffice and Account tests, and consolidate the CI code-style workflow May 14, 2026
@tjementum tjementum changed the title Share WebApplicationFactory across BackOffice and Account tests, and consolidate the CI code-style workflow Speed up CI and local format and lint May 14, 2026
@tjementum tjementum changed the title Speed up CI and local format and lint Speed up CI and format and lint CLI commands May 14, 2026
@tjementum tjementum force-pushed the pp-1209-share-webapplicationfactory-across-tests branch from 9587ec5 to 3d75764 Compare May 15, 2026 18:10
@tjementum tjementum force-pushed the pp-1209-share-webapplicationfactory-across-tests branch from ac2ad19 to a157c35 Compare May 15, 2026 20:16
@tjementum tjementum force-pushed the pp-1209-share-webapplicationfactory-across-tests branch 2 times, most recently from cc99d29 to 70c2a53 Compare May 15, 2026 20:40
@tjementum tjementum changed the title Speed up CI and format and lint CLI commands Refine CI/CD: speed up runs, scope developer CLI, and harden workflow hygiene May 15, 2026
@tjementum tjementum force-pushed the pp-1209-share-webapplicationfactory-across-tests branch from 70c2a53 to 2f872a7 Compare May 15, 2026 21:06
@tjementum tjementum force-pushed the pp-1209-share-webapplicationfactory-across-tests branch from 2f872a7 to 597bad9 Compare May 15, 2026 21:30
…llers re-write the same deterministic value instead of throwing
@tjementum tjementum changed the title Refine CI/CD: speed up runs, scope developer CLI, and harden workflow hygiene Speed up CI/CD runs, scope the developer CLI, and harden workflow hygiene May 15, 2026
@tjementum tjementum force-pushed the pp-1209-share-webapplicationfactory-across-tests branch 2 times, most recently from 52e32ce to 1bf55a9 Compare May 15, 2026 21:49
@sonarqubecloud
Copy link
Copy Markdown

@tjementum tjementum merged commit a53fab5 into main May 15, 2026
65 checks passed
@tjementum tjementum deleted the pp-1209-share-webapplicationfactory-across-tests branch May 15, 2026 21:55
@github-project-automation github-project-automation Bot moved this from 🏗 In Progress to ✅ Done in Kanban board May 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Enhancement New feature or request

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

1 participant